/*****************************************************************************************
 * ETS
 * 
 * Cours:		LOG121
 * Session:		A2013
 * Groupe:		04
 * Projet:		Laboratoire #4
 * Etudiants:	Frederic-Simon Mimeault
 * 				Francisco Felipe Quilodran
 * 				Guillaume Longtin
 * 				William Proulx
 * 
 * Professeur:	Francis Cardinal
 * 
 * Fichier:		FigureVue.java
 * Description:
 * 		
 * 
 * Date de creation:	2013-11-23
 * Date dern. modif.:	2013-12-06
 * ****************************************************************************************
 * Historique des modifications
 * ****************************************************************************************
 * 2013-11-23 Version initiale
 *****************************************************************************************/

package vue;

import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.Serializable;
import java.util.Observable;
import java.util.Observer;
import javax.swing.JFrame;
import javax.swing.JPanel;

import application.Menu;
import application.StrategieFermerFenetre;
import modele.Figure;
import modele.Perspective;
import controleur.GestionnaireCommande;

/**
 * Classe concrete qui permettra d'afficher une image avec un perspective.
 * @author Francisco Quilodran
 */
public class FigureVue extends JFrame implements Observer, Serializable {
	
	private BufferedImage imageCopy;
	public static final int WIDTH = 500;
	public static final int HEIGHT = 500;
	public static final Dimension DIMENSION = new Dimension(WIDTH, HEIGHT);
	private Figure figure;
	private Perspective perspective;
	private BufferedImage imageFinale;
	private JPanel panel;
	private Point pointDepart;
	
	/**
	 * Constructeur de FigureVue
	 * Il est possible zommer, dezommer, faire, defaire, ouvrir une nouvelle image, sauvegarder un projet et ouvrir un projet.
	 * @param figurePrincipale référence de la figure
	 * @param perspective référence de la perspective
	 * @param JMenuBar Menu de la fenêtre
	 * @param stratFermerFenetre Strategie pour fermer la fenêtre
	 */
	public FigureVue(Figure figurePrincipale, Perspective perspective, Menu JMenuBar, StrategieFermerFenetre stratFermerFenetre) {
		
		super();
		this.perspective = perspective;
		this.figure = figurePrincipale;
		stratFermerFenetre.setCloseBtnFuction(this);
		this.perspective.addObserver(this);
		this.figure.addObserver(this);
		this.setVisible(true);
		
		if(JMenuBar!=null) {
			
			this.setJMenuBar(JMenuBar);
			
		}
	   
	    imageCopy = figure.getImg();
	    imageFinale = imageCopy.getSubimage(perspective.getCoordonneeX(), perspective.getCoordonneeX(), WIDTH, HEIGHT);
		
	    panel = new JPanel() {
	
			private static final long serialVersionUID = 1L;

			@Override
			public void paint(Graphics g) {
				
				//http://stackoverflow.com/questions/4216123/how-to-scale-a-bufferedimage
				super.paint(g);
				((Graphics2D) g).drawImage(imageFinale,null,0,0);
			     g.dispose();
			     
			}
			
		};
		
		panel.addMouseListener(new MouseListener() {

			@Override
			public void mouseClicked(MouseEvent e){
				
			}

			@Override
			public void mouseEntered(MouseEvent e) {
				
				if(FigureVue.this.panel.getCursor().getType() == Cursor.DEFAULT_CURSOR) {
					
					FigureVue.this.panel.setCursor(new Cursor(Cursor.HAND_CURSOR));
					
				}
				
			}

			@Override
			public void mouseExited(MouseEvent e) {
				
				if(FigureVue.this.panel.getCursor().getType() != Cursor.DEFAULT_CURSOR) {
					
					FigureVue.this.panel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
					
				}
				
			}

			@Override
			public void mousePressed(MouseEvent e) {	
					
				pointDepart = new Point(e.getX(), e.getY());
				
			}
			
			@Override
			public void mouseReleased(MouseEvent e) {
				
				int deplacementX = (int) (pointDepart.getX() - e.getX());
				int deplacementY = (int) (pointDepart.getY() - e.getY());
				GestionnaireCommande.getInstance().genererCmdTranslation(FigureVue.this.perspective, deplacementX, deplacementY);

			}	
			
		});
		
		panel.addMouseMotionListener(new MouseMotionListener() {

			@Override
			public void mouseDragged(MouseEvent e) {
				
				/*System.out.println(FigureVue.this.figure.getImg().getWidth());
				System.out.println(WIDTH+FigureVue.this.perspective.getCoordonneeX());
            	int prochainMouventX=((WIDTH+FigureVue.this.perspective.getCoordonneeX())+(pointDepart.x-e.getX()));
				int prochainMouventY=((HEIGHT+FigureVue.this.perspective.getCoordonneeY())+(pointDepart.y-e.getY()));
				System.out.println("prochain mouvement est : "+ ((WIDTH+FigureVue.this.perspective.getCoordonneeX())+(pointDepart.x-e.getX())));
				if((FigureVue.this.figure.getImg().getWidth()>prochainMouventX)&&(FigureVue.this.figure.getImg().getHeight()>(prochainMouventY)))
				{
					GestionnaireCommande.getInstance().ajouterCommande(GestionnaireCommande.getInstance().genererCmdTranslation(FigureVue.this.perspective,e.getX(),e.getY()));
				}//FigureVue.this.imageFinal=FigureVue.this.figure.getImg().getSubimage(FigureVue.this.pointCentre-e.getX(), getY(), 500, 500);
				FigureVue.this.repaint();
				*/
			}

			@Override
			public void mouseMoved(MouseEvent e) {
				
				
			}
		});
		
		panel.addMouseWheelListener(new MouseWheelListener() {
	
			@Override
			public void mouseWheelMoved(MouseWheelEvent arg0) {
				
				int echelle = 0;
				int nbClick = 0;
				int tempcalculEchelle;
				
				nbClick = arg0.getWheelRotation();
				
				//Note: si le nombre de click est negatif, cela veut dire que le 
				if(nbClick < 0) {
					
					//(Scroll up)
					tempcalculEchelle=(10 * nbClick * -1);
					double echelleReal=((double)FigureVue.this.perspective.getEchelle() / 100);
					FigureVue.this.scaleImage(echelleReal);
					GestionnaireCommande.getInstance().genererCmdZoom(FigureVue.this.perspective, tempcalculEchelle);
					
				} else {
					
					tempcalculEchelle=( 10 * nbClick * -1);
					double echelleReal=((double)FigureVue.this.perspective.getEchelle() / 100);
					FigureVue.this.scaleImage(echelleReal);
					GestionnaireCommande.getInstance().genererCmdZoom(FigureVue.this.perspective, tempcalculEchelle);
					
				}
			}
			
		});
		
		panel.setPreferredSize(new Dimension(300,300));
		this.setResizable(false);
		this.pack();
		this.setContentPane(panel);
		this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
	}
	
	@Override
	public void paintComponents(Graphics g) {
		
		super.paintComponents(g);
		
	}
	
	private static final long serialVersionUID = -8001513251567805994L;

	@Override
	public void update(Observable arg0, Object arg1) {
		
		if(arg1 instanceof Perspective) {
			  
			this.scaleImage((double)perspective.getEchelle() / 100);
			
		}
		imageFinale = FigureVue.this.imageCopy.getSubimage(perspective.getCoordonneeX(), perspective.getCoordonneeY(), 500, 500);
	    FigureVue.this.repaint();
	}
	
	@Override
	public Dimension getPreferredSize() {
		
		return DIMENSION;
		
	}
	
	/**
	 * Méthode qui ajuste une image selon un echelle de 0.1 à 1.0 (10% à 100%) 
	 * @param echelle echelle de graduation du changement.
	 */
	private void scaleImage(double echelle) {
		
		AffineTransform affineTranform = AffineTransform.getScaleInstance(echelle, echelle);
		AffineTransformOp scaleOp = new AffineTransformOp(affineTranform, AffineTransformOp.TYPE_BILINEAR);
		imageCopy = new BufferedImage(FigureVue.this.figure.getImg().getWidth(), FigureVue.this.figure.getImg().getHeight(), BufferedImage.TYPE_3BYTE_BGR);
		scaleOp.filter(FigureVue.this.figure.getImg(), imageCopy);
		
	}
}
